using System.Collections;
using System.Collections.Specialized;
using Microsoft.SharePoint.StsAdmin;
using System;
using System.Diagnostics;
using System.IO;
using Microsoft.SharePoint;
using System.Reflection;

namespace $ApplicationNamespace$.$ApplicationName$.STSADMExtension.$WSPSolutionName$
{
    public class SPParam
    {
        private bool m_bEnabled;
        private bool m_bIsFlag;
        private bool m_bIsRequired;
        private bool m_bUserTypedIn;
        private string m_strDefaultValue;
        private string m_strHelpMessage;
        private string m_strName;
        private string m_strShortName;
        private string m_strValue;
        private ISPValidator m_Validator;
        private ArrayList m_Validators;

        /// <summary>
        /// Initializes a new instance of the <see cref="SPParam"/> class.
        /// </summary>
        /// <param name="strName">Name of the STR.</param>
        /// <param name="strShortName">Short name of the STR.</param>
        public SPParam(string strName, string strShortName)
        {
            m_strName = strName;
            m_strShortName = strShortName;
            m_bIsFlag = true;
            m_bEnabled = true;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SPParam"/> class.
        /// </summary>
        /// <param name="strName">Name of the STR.</param>
        /// <param name="strShortName">Short name of the STR.</param>
        /// <param name="bIsRequired">if set to <c>true</c> [b is required].</param>
        /// <param name="strDefaultValue">The STR default value.</param>
        /// <param name="validator">The validator.</param>
        public SPParam(string strName, string strShortName, bool bIsRequired, string strDefaultValue, ISPValidator validator)
            : this(strName, strShortName, bIsRequired, strDefaultValue, validator, "")
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SPParam"/> class.
        /// </summary>
        /// <param name="strName">Name of the STR.</param>
        /// <param name="strShortName">Short name of the STR.</param>
        /// <param name="bIsRequired">if set to <c>true</c> [b is required].</param>
        /// <param name="strDefaultValue">The STR default value.</param>
        /// <param name="validator">The validator.</param>
        /// <param name="strHelpMessage">The STR help message.</param>
        public SPParam(string strName, string strShortName, bool bIsRequired, string strDefaultValue, ISPValidator validator, string strHelpMessage)
        {
            m_strName = strName;
            m_strShortName = strShortName;
            m_bIsRequired = bIsRequired;
            m_strDefaultValue = strDefaultValue;
            m_Validator = validator;
            m_strHelpMessage = strHelpMessage;
            m_bEnabled = true;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SPParam"/> class.
        /// </summary>
        /// <param name="strName">Name of the STR.</param>
        /// <param name="strShortName">Short name of the STR.</param>
        /// <param name="bIsRequired">if set to <c>true</c> [b is required].</param>
        /// <param name="strDefaultValue">The STR default value.</param>
        /// <param name="validators">The validators.</param>
        /// <param name="strHelpMessage">The STR help message.</param>
        public SPParam(string strName, string strShortName, bool bIsRequired, string strDefaultValue, ArrayList validators, string strHelpMessage)
        {
            m_strName = strName;
            m_strShortName = strShortName;
            m_bIsRequired = bIsRequired;
            m_strDefaultValue = strDefaultValue;
            m_strHelpMessage = strHelpMessage;
            m_bEnabled = true;
            m_Validators = validators;
        }

        /// <summary>
        /// Inits the value from.
        /// </summary>
        /// <param name="keyValues">The key values.</param>
        public void InitValueFrom(StringDictionary keyValues)
        {
            m_strValue = keyValues[Name];
            if (m_strValue == null)
            {
                m_strValue = keyValues[ShortName];
            }
            m_bUserTypedIn = m_strValue != null;
            if (m_strValue == string.Empty)
                m_strValue = null;
        }

        private string m_errorInfo = null;
        public virtual string ErrorInfo
        {
            get { return m_errorInfo; }
            private set { m_errorInfo = value; }
        }

        /// <summary>
        /// Validates this instance.
        /// </summary>
        /// <returns></returns>
        public bool Validate()
        {
            if (!m_bIsFlag)
            {
                if (m_Validator == null)
                {
                    if (m_Validators != null)
                    {
                        foreach (ISPValidator validator in m_Validators)
                        {
                            if (!validator.Validate(Value))
                            {
                                ErrorInfo = validator.ErrorInfo;
                                return false;
                            }
                        }
                        return true;
                    }
                    else
                    {
                        return true;
                    }
                }
                if (!m_Validator.Validate(Value))
                {
                    ErrorInfo = m_Validator.ErrorInfo;
                    return false;
                }
            }
            else
            {
                return ((m_strValue == null) || (m_strValue.Trim().Length == 0));
            }
            return true;
        }

        /// <summary>
        /// Gets the default value.
        /// </summary>
        /// <value>The default value.</value>
        public string DefaultValue
        {
            get
            {
                return m_strDefaultValue;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="SPParam"/> is enabled.
        /// </summary>
        /// <value><c>true</c> if enabled; otherwise, <c>false</c>.</value>
        public bool Enabled
        {
            get
            {
                return m_bEnabled;
            }
            set
            {
                m_bEnabled = value;
            }
        }

        /// <summary>
        /// Gets the help message.
        /// </summary>
        /// <value>The help message.</value>
        public string HelpMessage
        {
            get
            {
                return m_strHelpMessage;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is flag.
        /// </summary>
        /// <value><c>true</c> if this instance is flag; otherwise, <c>false</c>.</value>
        public bool IsFlag
        {
            get
            {
                return m_bIsFlag;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is required.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is required; otherwise, <c>false</c>.
        /// </value>
        public bool IsRequired
        {
            get
            {
                return m_bIsRequired;
            }
            set
            {
                m_bIsRequired = value;
            }
        }

        /// <summary>
        /// Gets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name
        {
            get
            {
                return m_strName;
            }
        }

        /// <summary>
        /// Gets the short name.
        /// </summary>
        /// <value>The short name.</value>
        public string ShortName
        {
            get
            {
                return m_strShortName;
            }
        }

        /// <summary>
        /// Gets a value indicating whether [user typed in].
        /// </summary>
        /// <value><c>true</c> if [user typed in]; otherwise, <c>false</c>.</value>
        public bool UserTypedIn
        {
            get
            {
                return m_bUserTypedIn;
            }
        }

        /// <summary>
        /// Gets the value.
        /// </summary>
        /// <value>The value.</value>
        public string Value
        {
            get
            {
                if (UserTypedIn)
                {
                    return m_strValue;
                }
                return m_strDefaultValue;
            }
        }
    }

    public abstract class SPOperation : ISPStsadmCommand
    {
        protected const int OUTPUT_SUCCESS = 0;
        private SPParamCollection m_params;
        private string m_helpMessage;
        private static bool m_Verbose;
        private static string m_LogFile = null;

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="SPOperation"/> is verbose.
        /// </summary>
        /// <value><c>true</c> if verbose; otherwise, <c>false</c>.</value>
        public static bool Verbose
        {
            get { return m_Verbose; }
            set { m_Verbose = value; }
        }

        /// <summary>
        /// Gets or sets the log file.
        /// </summary>
        /// <value>The log file.</value>
        public static string LogFile
        {
            get { return m_LogFile; }
            set { m_LogFile = value; }
        }



        // 98d3057cd9024c27b2007643c1 is a special hard coded name for a list that Microsoft uses to store the mapping
        // of URLs from v2 to v3 (maps the bucket urls to the new urls).
        protected const string UPGRADE_AREA_URL_LIST = "98d3057cd9024c27b2007643c1";


        /// <summary>
        /// Logs the specified message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="args">The args.</param>
        internal static void Log(string message, params string[] args)
        {
            Log(message, EventLogEntryType.Information, args);
        }

        /// <summary>
        /// Logs the specified STR.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="msgType">Type of the MSG.</param>
        /// <param name="args">The args.</param>
        internal static void Log(string message, EventLogEntryType msgType, params string[] args)
        {
            message = string.Format(message, args);
            if (msgType != EventLogEntryType.Information || Verbose)
            {
                Console.WriteLine(message);
            }
            if (!string.IsNullOrEmpty(m_LogFile))
                File.AppendAllText(m_LogFile, message + "\r\n");
        }

        /// <summary>
        /// Inits the specified parameters.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <param name="helpMessage">The help message.</param>
        protected void Init(SPParamCollection parameters, string helpMessage)
        {
            helpMessage = helpMessage.TrimEnd(new char[] { '\r', '\n' });
#if DEBUG
            helpMessage += "\r\n\t[-debug]";
            parameters.Add(new SPParam("debug", "debug"));
#endif

            m_params = parameters;

            helpMessage +=
                "\r\n\r\n\r\nCopyright 2008 Gary smc\r\n  > For more information on this command and others:\r\n  > http://stsadm.blogspot.com/\r\n  > Use of this command is at your own risk.\r\n  > Gary smc assumes no liability.";
            m_helpMessage = helpMessage;
        }

        /// <summary>
        /// Inits the parameters.
        /// </summary>
        /// <param name="keyValues">The key values.</param>
        public virtual void InitParameters(StringDictionary keyValues)
        {
            foreach (SPParam param in Params)
            {
                param.InitValueFrom(keyValues);
            }
            Validate(keyValues);
#if DEBUG
            if (Params["debug"].UserTypedIn)
                Debugger.Launch();
#endif
        }


        /// <summary>
        /// Validates the specified key values.
        /// </summary>
        /// <param name="keyValues">The key values.</param>
        public virtual void Validate(StringDictionary keyValues)
        {
            string strMessage = null;

            foreach (string current in keyValues.Keys)
            {
                if (current != "o" && Params[current] == null)
                {
                    strMessage += string.Format("Command line error. Invalid parameter: {0}.\r\n", current);
                }
            }
            if (strMessage != null)
                throw new SPSyntaxException(strMessage);

            foreach (SPParam param in Params)
            {
                if (param.Enabled)
                {
                    if (param.IsRequired && !param.UserTypedIn)
                    {
                        strMessage += SPResource.GetString("MissRequiredArg", new object[] { param.Name }) + "\r\n";
                    }
                }
            }
            if (strMessage != null)
                throw new SPSyntaxException(strMessage);

            foreach (SPParam param in Params)
            {
                if (param.Enabled)
                {
                    if (param.UserTypedIn && !param.Validate())
                    {
                        strMessage += SPResource.GetString("InvalidArg", new object[] { param.Name });
                        if (!string.IsNullOrEmpty(param.ErrorInfo))
                            strMessage += string.Format(" ({0})", param.ErrorInfo);

                        if (!string.IsNullOrEmpty(param.HelpMessage))
                        {
                            strMessage += "\r\n\t" + param.HelpMessage + "\r\n";
                        }
                    }
                }
            }
            if (strMessage != null)
                throw new SPSyntaxException(strMessage);
        }

        // Properties
        public virtual string DisplayNameId
        {
            get
            {
                return null;
            }
        }



        public string HelpMessage
        {
            get
            {
                return m_helpMessage;
            }
        }

        protected internal SPParamCollection Params
        {
            get
            {
                return m_params;
            }
        }

        /// <summary>
        /// Executes the specified command.
        /// </summary>
        /// <param name="command">The command.</param>
        /// <param name="keyValues">The key values.</param>
        /// <param name="output">The output.</param>
        /// <returns></returns>
        public abstract int Execute(string command, StringDictionary keyValues, out string output);

        #region ISPStsadmCommand Members

        /// <summary>
        /// Gets the help message.
        /// </summary>
        /// <param name="command">The command.</param>
        /// <returns></returns>
        public abstract string GetHelpMessage(string command);

        /// <summary>
        /// Runs the specified command.
        /// </summary>
        /// <param name="command">The command.</param>
        /// <param name="keyValues">The key values.</param>
        /// <param name="output">The output.</param>
        /// <returns></returns>
        public virtual int Run(string command, StringDictionary keyValues, out string output)
        {
            output = string.Empty;
            try
            {
                InitParameters(keyValues);

                return Execute(command, keyValues, out output);
            }
            catch (TargetInvocationException ex)
            {
                if (ex.InnerException != null)
                    throw ex.InnerException;
                else
                    throw;
            }
            catch (SPSyntaxException ex)
            {
                output += ex.Message;
                return (int)ErrorCodes.SyntaxError;
            }
        }

        #endregion
    }

    public class SPParamCollection : IEnumerable
    {
        // Fields
        private ArrayList m_Collection = new ArrayList();
        private Hashtable m_NameMap = new Hashtable();
        private Hashtable m_ShortNameMap = new Hashtable();

        // Methods
        public void Add(SPParam param)
        {
            m_Collection.Add(param);
            m_NameMap.Add(param.Name, param);
            m_ShortNameMap.Add(param.ShortName, param);
        }

        public IEnumerator GetEnumerator()
        {
            return m_Collection.GetEnumerator();
        }

        // Properties
        public int Count
        {
            get
            {
                return m_Collection.Count;
            }
        }

        public SPParam this[string strName]
        {
            get
            {
                SPParam param = (SPParam)m_NameMap[strName];
                if (param != null)
                {
                    return param;
                }
                return (SPParam)m_ShortNameMap[strName];
            }
        }

        public SPParam this[int index]
        {
            get
            {
                return (SPParam)m_Collection[index];
            }
        }
    }

    internal class SPSyntaxException : ApplicationException
    {
        // Methods
        public SPSyntaxException(string strMessage)
            : base(strMessage)
        {
        }
    }

 
}
